﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Samurai.Validation.Specs.StaticMocks;
using Samurai.Wakizashi.Validation;

namespace Samurai.Validation.Specs
{
    [TestClass]
    public class FluentInterface_Specification
    {
        [TestMethod]
        public void Validates_email_address_format_using_fluent_interface()
        {
            var c = new Customer { EmailAddress = "jdoe@somewhere.com" };
            var validator = new Validator<Customer>(c);

            //Should pass
            validator.FlushRules();
            var result1 = validator.For(x => c.EmailAddress).Ensure().IsEmailAddress().Validate();

            //Should fail
            c.EmailAddress = "thisshouldfail@";
            validator.FlushRules();
            var result2 = validator.For(x => c.EmailAddress).Ensure().IsEmailAddress().Validate();

            Assert.IsTrue(result1.IsValid && !result2.IsValid);
        }

        [TestMethod]
        public void Validates_string_is_longer_than_number_using_fluent_interface()
        {
            var c = new Customer { Nickname = "xxx" };
            var validator = new Validator<Customer>(c);

            //Should fail
            validator.FlushRules();
            var result1 = validator.For(x => c.Nickname).Ensure().IsLongerThan(3).Validate();

            //Should pass
            c.Nickname = "xxxx";
            validator.FlushRules();
            var result2 = validator.For(x => c.Nickname).Ensure().IsLongerThan(3).Validate();

            Assert.IsTrue(!result1.IsValid && result2.IsValid);
        }

        [TestMethod]
        public void Validates_string_is_shorter_than_number_using_fluent_interface()
        {
            var c = new Customer { Nickname = "xxx" };
            var validator = new Validator<Customer>(c);

            //Should fail
            validator.FlushRules();
            var result1 = validator.For(x => c.Nickname).Ensure().IsShorterThan(3).Validate();

            //Should pass
            c.Nickname = "xx";
            validator.FlushRules();
            var result2 = validator.For(x => c.Nickname).Ensure().IsShorterThan(3).Validate();

            Assert.IsTrue(!result1.IsValid && result2.IsValid);
        }

        [TestMethod]
        public void Validates_url_format_using_fluent_interface()
        {
            var c = new Customer { Nickname = "http://www.google.com" };
            var validator = new Validator<Customer>(c);

            //Should pass
            validator.FlushRules();
            var result1 = validator.For(x => c.Nickname).Ensure().IsUrl().Validate();

            //Should fail
            c.Nickname = "thishouldfail";
            validator.FlushRules();
            var result2 = validator.For(x => c.Nickname).Ensure().IsUrl().Validate();

            result1.IsValid.ShouldBeTrue();
            result2.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void Validates_target_date_is_earlier_than_given_date_using_fluent_interface()
        {
            var c = new Customer { BirthDate = new DateTime(1974,1,9) };
            var validator = new Validator<Customer>(c);

            //Should pass
            validator.FlushRules();
            var result1 = validator.For(x => c.BirthDate).Ensure().IsEarlierThan(new DateTime(1980,1,1)).Validate();

            //Should fail
            validator.FlushRules();
            var result2 = validator.For(x => c.BirthDate).Ensure().IsEarlierThan(new DateTime(1970,1,1)).Validate();

            result1.IsValid.ShouldBeTrue();
            result2.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void Validates_target_date_is_later_than_given_date_using_fluent_interface()
        {
            var c = new Customer { BirthDate = new DateTime(1974, 1, 9) };
            var validator = new Validator<Customer>(c);

            //Should pass
            validator.FlushRules();
            var result1 = validator.For(x => c.BirthDate).Ensure().IsLaterThan(new DateTime(1970, 1, 1)).Validate();

            //Should fail
            validator.FlushRules();
            var result2 = validator.For(x => c.BirthDate).Ensure().IsLaterThan(new DateTime(1980, 1, 1)).Validate();

            result1.IsValid.ShouldBeTrue();
            result2.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void Validates_target_property_is_not_null_using_fluent_interface()
        {
            var c = new Customer { SomeObjectProperty = new SomeObject() };
            var validator = new Validator<Customer>(c);

            //Should pass
            validator.FlushRules();
            var result1 = validator.For(x => c.SomeObjectProperty).Ensure().IsNotNull().Validate();

            //Should fail
            validator.FlushRules();
            c.SomeObjectProperty = null;
            var result2 = validator.For(x => c.SomeObjectProperty).Ensure().IsNotNull().Validate();

            result1.IsValid.ShouldBeTrue();
            result2.IsValid.ShouldBeFalse();
        }

        [TestMethod]
        public void Validates_target_property_is_not_an_empty_Guid_using_fluent_interface()
        {
            var c = new Customer { SomeObjectProperty = new SomeObject() };
            var validator = new Validator<Customer>(c);

            //Should pass
            validator.FlushRules();
            var result1 = validator.For(x => c.SomeObjectProperty).Ensure().IsNotNull().Validate();

            //Should fail
            validator.FlushRules();
            c.SomeGuid = Guid.Empty;
            var result2 = validator.For(x => c.SomeGuid).Ensure().IsNotEmpty().Validate();

            result1.IsValid.ShouldBeTrue();
            result2.IsValid.ShouldBeFalse();
        }
    }
}
